#ifndef __Observer_H__
#define __Observer_H__

#include <list>
#include <algorithm>
#include <string>
#include <iostream>
using std::string;
using std::list;
using std::cout;
using std::endl;

struct Status
{
    Status(int cnt)
    : _cnt(cnt)
    {}
    virtual ~Status() {}

    int _cnt;
};

class Subject;//前向声明

class Observer
{
public:
    Observer()
    : _psubject(nullptr)
    , _pstatus(nullptr)
    {}

    Observer(Subject * s)
    : _psubject(s)
    , _pstatus(nullptr)
    {}

    virtual void update() = 0;

    virtual ~Observer() {}

protected:
    Subject * _psubject;
    Status * _pstatus;
};

class Subject
{
public:
    Subject()
    : _status(nullptr)
    {}

    void attach(Observer * ob)
    {
        auto it = std::find(_obList.begin(), _obList.end(), ob);
        if(it == _obList.end()) {
            //没有找到情况下， 就添加到list中
            _obList.push_back(ob);
        }
    }

    void detach(Observer * ob)
    {
        auto it = std::find(_obList.begin(), _obList.end(), ob);
        if(it != _obList.end()) {
            //找到情况下， 就从list中删除
            _obList.erase(it);
        }
    }

    virtual void setStatus(Status * s)
    {   _status = s;    }

    virtual Status * getStatus() const
    {   return _status; }

    //通知所有的观察者
    void notify()
    {
        auto it = _obList.begin();
        while(it != _obList.end()) {
            (*it)->update();
            ++it;
        }
    }

    virtual ~Subject() {}

protected:
    Status * _status;
    list<Observer*> _obList;
};


struct FoodStatus
: public Status
{
    FoodStatus(int cnt, const string & name)
    : Status(cnt),
    _name(name)
    {}
    string _name;

    ~FoodStatus() { cout << "~FoodStatus()" << endl;    }
};

class Food
: public Subject
{
public:
    //传递过来的美食信息是一个堆空间的对象
    void  setStatus(Status * s) override
    {
        //先回收原来的美食信息
        if(_status) {
            delete _status;
        }
        //更换美食了
        _status = s;
        FoodStatus * pfood = dynamic_cast<FoodStatus*>(_status);
        if(pfood) {
            cout << ">> 早晚稻新添加了" << pfood->_cnt << "道" << pfood->_name << endl;
            //通知所有的观察者
            notify();
        }
    }
    
    ~Food() {
        cout << "~Food()" << endl;
        if(_status) {
            delete _status;
        }
    }

};

class User
: public Observer
{
public:
    User(Subject * subject, const string & name)
    : Observer(subject) 
    , _name(name)
    {}

    void update() 
    {
        //先获取主题的状态
        //更新状态的操作
        _pstatus = _psubject->getStatus();
        FoodStatus * foodStatus = dynamic_cast<FoodStatus*>(_pstatus);
        if(foodStatus) {
            cout << "用户:" << _name << "点了一道美食" << foodStatus->_name << endl;
            foodStatus->_cnt--;
        }
    }

    ~User()
    {   cout << "~User()" << endl;  }
private:
    string _name;
};

class VipUser
: public Observer
{
public:
    VipUser(Subject * subject, const string & name)
    : Observer(subject)
    , _name(name)
    {}

    void update()
    {
        _pstatus = _psubject->getStatus();
        //dynamic_cast的动态转换就很关键了
        FoodStatus * foodStatus = dynamic_cast<FoodStatus*>(_pstatus);
        if(foodStatus) {
            if(foodStatus->_cnt > 10) {
                cout << "Vip用户:" << _name << "点了10道美食" << foodStatus->_name << endl;
                foodStatus->_cnt -= 10;
            } else if( foodStatus->_cnt > 5 )
            {
                cout << "Vip用户:" << _name << "点了5道美食" << foodStatus->_name << endl;
                foodStatus->_cnt -= 5;
            }
        }
    }

    ~VipUser()
    {   cout << "~VipUser()" << endl;   }

private:
    string _name;
};


#endif

